package com.sneakxy.cloudbase.platform.interceptor;

import java.lang.reflect.Method;
import java.util.Collection;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.aop.MethodInvocation;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.aop.AuthorizingAnnotationMethodInterceptor;
import org.apache.shiro.spring.security.interceptor.AopAllianceAnnotationsAuthorizingMethodInterceptor;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.sneakxy.cloudbase.platform.utils.web.signature.RequireSignature;
import com.sneakxy.cloudbase.platform.utils.web.signature.SignatureContext;
import com.sneakxy.cloudbase.platform.utils.web.signature.SignatureErrorException;
import com.sneakxy.cloudbase.platform.utils.web.signature.SignatureValidator;

public class CloudBaseAopAllianceAnnotationsAuthorizingMethodInterceptor
		extends AopAllianceAnnotationsAuthorizingMethodInterceptor {

	private SignatureValidator signatureValidator;

	public CloudBaseAopAllianceAnnotationsAuthorizingMethodInterceptor() {
	}

	public CloudBaseAopAllianceAnnotationsAuthorizingMethodInterceptor(SignatureValidator signatureValidator) {
		this.signatureValidator = signatureValidator;
	}

	@Override
	protected void assertAuthorized(MethodInvocation methodInvocation) throws AuthorizationException {
		if (hasRequireSignature(methodInvocation)) {
			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
					.getRequest();
			String signature = request.getHeader(SignatureContext.SIGNATURE);
			if (StringUtils.isNotBlank(signature)) {
				signatureValidator.validate(signature);
				return;
			} else {
				//无其他注解
				if(!support(methodInvocation)) {
					throw new SignatureErrorException("缺少签名");
				}
			}
		}
		super.assertAuthorized(methodInvocation);
	}

	protected boolean support(MethodInvocation methodInvocation) {
		// default implementation just ensures no deny votes are cast:
		Collection<AuthorizingAnnotationMethodInterceptor> aamis = getMethodInterceptors();
		if (aamis != null && !aamis.isEmpty()) {
			for (AuthorizingAnnotationMethodInterceptor aami : aamis) {
				if (aami.supports(methodInvocation)) {
					return true;
				}
			}
		}
		return false;
	}
	
	protected boolean hasRequireSignature(MethodInvocation methodInvocation) {
		Method method = methodInvocation.getMethod();
		if (method == null) {
			return false;
		}
		return method.getAnnotation(RequireSignature.class) != null;
	}

	public SignatureValidator getSignatureValidator() {
		return signatureValidator;
	}

	public void setSignatureValidator(SignatureValidator signatureValidator) {
		this.signatureValidator = signatureValidator;
	}

}
